Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Tape is a minimalist JavaScript testing framework for Node.js. It provides a simple and straightforward way to write tests for your code, focusing on simplicity and ease of use.
Basic Test
This feature allows you to write basic tests. The example demonstrates a simple test that checks if the sum of 1 and 1 equals 2.
const test = require('tape');
test('Basic test', function (t) {
t.plan(1);
t.equal(1 + 1, 2, '1 + 1 should equal 2');
});
Asynchronous Test
This feature allows you to write asynchronous tests. The example demonstrates a test that performs an assertion after a 1-second delay.
const test = require('tape');
test('Asynchronous test', function (t) {
t.plan(1);
setTimeout(function () {
t.equal(1 + 1, 2, '1 + 1 should equal 2');
}, 1000);
});
Nested Tests
This feature allows you to write nested tests. The example demonstrates a parent test containing a child test.
const test = require('tape');
test('Parent test', function (t) {
t.test('Child test', function (st) {
st.plan(1);
st.equal(1 + 1, 2, '1 + 1 should equal 2');
});
t.end();
});
Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. It provides a variety of interfaces (e.g., BDD, TDD) and supports a wide range of reporters. Compared to Tape, Mocha is more feature-rich and flexible but also more complex.
Jest is a delightful JavaScript testing framework with a focus on simplicity. It works out of the box for most JavaScript projects and includes features like snapshot testing and a built-in test runner. Compared to Tape, Jest is more opinionated and comes with more built-in features, making it easier to set up but less minimalistic.
AVA is a test runner for Node.js with a concise API, detailed error output, and process isolation. It runs tests concurrently, which can lead to faster test execution. Compared to Tape, AVA is more modern and provides better support for ES6/ES7 features, but it may be less familiar to those used to traditional test runners.
tap-producing test harness for node and browsers
var test = require('tape');
test('timing test', function (t) {
t.plan(2);
t.equal(typeof Date.now, 'function');
var start = Date.now();
setTimeout(function () {
t.equal(Date.now() - start, 100);
}, 100);
});
$ node example/timing.js
TAP version 13
# timing test
ok 1 should be equal
not ok 2 should be equal
---
operator: equal
expected: 100
actual: 107
...
1..2
# tests 2
# pass 1
# fail 1
You always need to require('tape')
in test files.
You can run the tests by usual node means (require('test-file.js')
or node test-file.js
).
You can also run tests using the tape
binary to utilize globbing, on Windows for example:
$ tape tests/**/*.js
tape
's arguments are passed to the glob
module.
If you want glob
to perform the expansion on a system where the shell performs such expansion, quote the arguments as necessary:
$ tape 'tests/**/*.js'
$ tape "tests/**/*.js"
Additionally, it is possible to make tape
load one or more modules before running any tests, by using the -r
or --require
flag. Here's an example that loads babel-register before running any tests, to allow for JIT compilation:
$ tape -r babel-register tests/**/*.js
Depending on the module you're loading, you may be able to parameterize it using environment variables or auxiliary files. Babel, for instance, will load options from .babelrc
at runtime.
The -r
flag behaves exactly like node's require
, and uses the same module resolution algorithm. This means that if you need to load local modules, you have to prepend their path with ./
or ../
accordingly.
For example:
$ tape -r ./my/local/module tests/**/*.js
Please note that all modules loaded using the -r
flag will run before any tests, regardless of when they are specified. For example, tape -r a b -r c
will actually load a
and c
before loading b
, since they are flagged as required modules.
tape
maintains a fairly minimal core. Additional features are usually added by using another module alongside tape
.
The default TAP output is good for machines and humans that are robots.
If you want a more colorful / pretty output there are lots of modules on npm that will output something pretty if you pipe TAP into them:
To use them, try node test/index.js | tap-spec
or pipe it into one of the modules of your choice!
By default, uncaught exceptions in your tests will not be intercepted, and will cause tape
to crash. If you find this behavior undesirable, use tape-catch
to report any exceptions as TAP errors.
While running tests, top-level configurations can be passed via the command line to specify desired behavior.
Available configurations are listed below:
Alias: -r
This is used to load modules before running tests and is explained extensively in the preloading modules section.
Alias: -i
This flag is used when tests from certain folders and/or files are not intended to be run. It defaults to .gitignore
file when passed with no argument.
tape -i .ignore **/*.js
An error is thrown if the specified file passed as argument does not exist.
This is particularly useful in a CI environment where an only test is not supposed to go unnoticed.
By passing the --no-only
flag, any existing only test causes tests to fail.
tape --no-only **/*.js
Alternatively, the environment variable NODE_TAPE_NO_ONLY_TEST
can be set to true
to achieve the same behavior; the command-line flag takes precedence.
The assertion methods in tape
are heavily influenced or copied from the methods in node-tap.
var test = require('tape')
Create a new test with an optional name
string and optional opts
object.
cb(t)
fires with the new test object t
once all preceding tests have finished.
Tests execute serially.
Available opts
options are:
NODE_TAPE_OBJECT_PRINT_DEPTH
can set the desired default depth for all tests; locally-set values will take precedence.If you forget to t.plan()
out how many assertions you are going to run and you don't call t.end()
explicitly, your test will hang.
Generate a new test that will be skipped over.
The onFinish hook will get invoked when ALL tape
tests have finished right before tape
is about to print the test summary.
fn
is called with no arguments, and its return value is ignored.
The onFailure hook will get invoked whenever any tape
tests has failed.
fn
is called with no arguments, and its return value is ignored.
Declare that n
assertions should be run. t.end()
will be called automatically after the n
th assertion.
If there are any more assertions after the n
th, or after t.end()
is called, they will generate errors.
Declare the end of a test explicitly. If err
is passed in t.end
will assert that it is falsy.
Do not call t.end()
if your test callback returns a Promise.
Register a callback to run after the individual test has completed. Multiple registered teardown callbacks will run in order. Useful for undoing side effects, closing network connections, etc.
Generate a failing assertion with a message msg
.
Generate a passing assertion with a message msg
.
Automatically timeout the test after X ms.
Generate an assertion that will be skipped over.
Assert that value
is truthy with an optional description of the assertion msg
.
Aliases: t.true()
, t.assert()
Assert that value
is falsy with an optional description of the assertion msg
.
Aliases: t.false()
, t.notok()
Assert that err
is falsy. If err
is non-falsy, use its err.message
as the description message.
Aliases: t.ifError()
, t.ifErr()
, t.iferror()
Assert that actual === expected
with an optional description of the assertion msg
.
Aliases: t.equals()
, t.isEqual()
, t.is()
, t.strictEqual()
,
t.strictEquals()
Assert that actual !== expected
with an optional description of the assertion msg
.
Aliases: t.notEquals()
, t.notStrictEqual()
, t.notStrictEquals()
,
t.isNotEqual()
, t.isNot()
, t.not()
, t.doesNotEqual()
, t.isInequal()
Assert that actual
and expected
have the same structure and nested values using node's deepEqual() algorithm with strict comparisons (===
) on leaf nodes and an optional description of the assertion msg
.
Aliases: t.deepEquals()
, t.isEquivalent()
, t.same()
Assert that actual
and expected
do not have the same structure and nested values using node's deepEqual() algorithm with strict comparisons (===
) on leaf nodes and an optional description of the assertion msg
.
Aliases: t.notDeepEquals
, t.notEquivalent()
, t.notDeeply()
, t.notSame()
,
t.isNotDeepEqual()
, t.isNotDeeply()
, t.isNotEquivalent()
,
t.isInequivalent()
Assert that actual
and expected
have the same structure and nested values using node's deepEqual() algorithm with loose comparisons (==
) on leaf nodes and an optional description of the assertion msg
.
Aliases: t.looseEqual()
, t.looseEquals()
Assert that actual
and expected
do not have the same structure and nested values using node's deepEqual() algorithm with loose comparisons (==
) on leaf nodes and an optional description of the assertion msg
.
Aliases: t.notLooseEqual()
, t.notLooseEquals()
Assert that the function call fn()
throws an exception. expected
, if present, must be a RegExp
, Function
, or Object
. The RegExp
matches the string representation of the exception, as generated by err.toString()
. For example, if you set expected
to /user/
, the test will pass only if the string representation of the exception contains the word user
. Any other exception will result in a failed test. The Function
is the exception thrown (e.g. Error
). Object
in this case corresponds to a so-called validation object, in which each property is tested for strict deep equality. As an example, see the following two tests--each passes a validation object to t.throws()
as the second parameter. The first test will pass, because all property values in the actual error object are deeply strictly equal to the property values in the validation object.
const err = new TypeError("Wrong value");
err.code = 404;
err.check = true;
// Passing test.
t.throws(
() => {
throw err;
},
{
code: 404,
check: true
},
"Test message."
);
This next test will fail, because all property values in the actual error object are not deeply strictly equal to the property values in the validation object.
const err = new TypeError("Wrong value");
err.code = 404;
err.check = "true";
// Failing test.
t.throws(
() => {
throw err;
},
{
code: 404,
check: true // This is not deeply strictly equal to err.check.
},
"Test message."
);
This is very similar to how Node's assert.throws()
method tests validation objects (please see the Node assert.throws() documentation for more information).
If expected
is not of type RegExp
, Function
, or Object
, or omitted entirely, any exception will result in a passed test. msg
is an optional description of the assertion.
Please note that the second parameter, expected
, cannot be of type string
. If a value of type string
is provided for expected
, then t.throws(fn, expected, msg)
will execute, but the value of expected
will be set to undefined
, and the specified string will be set as the value for the msg
parameter (regardless of what actually passed as the third parameter). This can cause unexpected results, so please be mindful.
Assert that the function call fn()
does not throw an exception. expected
, if present, limits what should not be thrown, and must be a RegExp
or Function
. The RegExp
matches the string representation of the exception, as generated by err.toString()
. For example, if you set expected
to /user/
, the test will fail only if the string representation of the exception contains the word user
. Any other exception will result in a passed test. The Function
is the exception thrown (e.g. Error
). If expected
is not of type RegExp
or Function
, or omitted entirely, any exception will result in a failed test. msg
is an optional description of the assertion.
Please note that the second parameter, expected
, cannot be of type string
. If a value of type string
is provided for expected
, then t.doesNotThrows(fn, expected, msg)
will execute, but the value of expected
will be set to undefined
, and the specified string will be set as the value for the msg
parameter (regardless of what actually passed as the third parameter). This can cause unexpected results, so please be mindful.
Create a subtest with a new test handle st
from cb(st)
inside the current test t
. cb(st)
will only fire when t
finishes. Additional tests queued up after t
will not be run until all subtests finish.
You may pass the same options that test()
accepts.
Print a message without breaking the tap output.
(Useful when using e.g. tap-colorize
where output is buffered & console.log
will print in incorrect order vis-a-vis tap output.)
Multiline output will be split by \n
characters, and each one printed as a comment.
Assert that string
matches the RegExp regexp
. Will fail when the first two arguments are the wrong type.
Assert that string
does not match the RegExp regexp
. Will fail when the first two arguments are the wrong type.
Replaces obj[method]
with the supplied implementation.
obj
must be a non-primitive, method
must be a valid property key (string or symbol), and implementation
, if provided, must be a function.
Calling the returned results()
function will return an array of call result objects.
The array of calls will be reset whenever the function is called.
Call result objects will match one of these forms:
{ args: [x, y, z], receiver: o, returned: a }
{ args: [x, y, z], receiver: o, threw: true, thrown: e }
The replacement will automatically be restored on test teardown.
You can restore it manually, if desired, by calling .restore()
on the returned results function.
Modeled after tap.
Wraps the supplied function.
The returned wrapper has a .calls
property, which is an array that will be populated with call result objects, described under t.capture()
.
Modeled after tap.
Similar to t.capture()``, but can be used to track get/set operations for any arbitrary property. Calling the returned
results()` function will return an array of call result objects.
The array of calls will be reset whenever the function is called.
Call result objects will match one of these forms:
{ type: 'get', value: '1.2.3', success: true, args: [x, y, z], receiver: o }
{ type: 'set', value: '2.4.6', success: false, args: [x, y, z], receiver: o }
If strictMode
is true
, and writable
is false
, and no get
or set
is provided, an exception will be thrown when obj[property]
is assigned to.
If strictMode
is false
in this scenario, nothing will be set, but the attempt will still be logged.
Providing both desc.get
and desc.set
are optional and can still be useful for logging get/set attempts.
desc
must be a valid property descriptor, meaning that get
/set
are mutually exclusive with writable
/value
.
Additionally, explicitly setting configurable
to false
is not permitted, so that the property can be restored.
Create a new test harness instance, which is a function like test()
, but with a new pending stack and test state.
By default the TAP output goes to console.log()
. You can pipe the output to someplace else if you htest.createStream().pipe()
to a destination stream on the first tick.
Like test([name], [opts], cb)
except if you use .only
this is the only test case that will run for the entire process, all other test cases using tape
will be ignored.
Check out how the usage of the --no-only flag could help ensure there is no .only
test running in a specified environment.
Create a stream of output, bypassing the default output stream that writes messages to console.log()
. By default stream
will be a text stream of TAP output, but you can get an object stream instead by setting opts.objectMode
to true
.
You can create your own custom test reporter using this createStream()
api:
var test = require('tape');
var path = require('path');
test.createStream().pipe(process.stdout);
process.argv.slice(2).forEach(function (file) {
require(path.resolve(file));
});
You could substitute process.stdout
for whatever other output stream you want, like a network connection or a file.
Pass in test files to run as arguments:
$ node tap.js test/x.js test/y.js
TAP version 13
# (anonymous)
not ok 1 should be equal
---
operator: equal
expected: "boop"
actual: "beep"
...
# (anonymous)
ok 2 should be equal
ok 3 (unnamed assert)
# wheee
ok 4 (unnamed assert)
1..4
# tests 4
# pass 3
# fail 1
Here's how you can render an object stream instead of TAP:
var test = require('tape');
var path = require('path');
test.createStream({ objectMode: true }).on('data', function (row) {
console.log(JSON.stringify(row))
});
process.argv.slice(2).forEach(function (file) {
require(path.resolve(file));
});
The output for this runner is:
$ node object.js test/x.js test/y.js
{"type":"test","name":"(anonymous)","id":0}
{"id":0,"ok":false,"name":"should be equal","operator":"equal","actual":"beep","expected":"boop","error":{},"test":0,"type":"assert"}
{"type":"end","test":0}
{"type":"test","name":"(anonymous)","id":1}
{"id":0,"ok":true,"name":"should be equal","operator":"equal","actual":2,"expected":2,"test":1,"type":"assert"}
{"id":1,"ok":true,"name":"(unnamed assert)","operator":"ok","actual":true,"expected":true,"test":1,"type":"assert"}
{"type":"end","test":1}
{"type":"test","name":"wheee","id":2}
{"id":0,"ok":true,"name":"(unnamed assert)","operator":"ok","actual":true,"expected":true,"test":2,"type":"assert"}
{"type":"end","test":2}
A convenient alternative to achieve the same:
// report.js
var test = require('tape');
test.createStream({ objectMode: true }).on('data', function (row) {
console.log(JSON.stringify(row)) // for example
});
and then:
$ tape -r ./report.js **/*.test.js
With npm do:
npm install tape --save-dev
Sometimes t.end()
doesn’t preserve the expected output ordering.
For instance the following:
var test = require('tape');
test('first', function (t) {
setTimeout(function () {
t.ok(1, 'first test');
t.end();
}, 200);
t.test('second', function (t) {
t.ok(1, 'second test');
t.end();
});
});
test('third', function (t) {
setTimeout(function () {
t.ok(1, 'third test');
t.end();
}, 100);
});
will output:
ok 1 second test
ok 2 third test
ok 3 first test
because second
and third
assume first
has ended before it actually does.
Use t.plan()
instead to let other tests know they should wait:
var test = require('tape');
test('first', function (t) {
+ t.plan(2);
setTimeout(function () {
t.ok(1, 'first test');
- t.end();
}, 200);
t.test('second', function (t) {
t.ok(1, 'second test');
t.end();
});
});
test('third', function (t) {
setTimeout(function () {
t.ok(1, 'third test');
t.end();
}, 100);
});
MIT
FAQs
tap-producing test harness for node and browsers
We found that tape demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.